import * as fs from "fs"
import { promisify } from "util"
import { UserAppDetail, UserAppTree } from "../interface"
import { getDocDir, getLoginUser } from "../config"
import { APIContext, LoginUser, RouterDecorator } from "f2e-server3"
import { getAppDetail } from "./app"
import { API, DIR_TYPE, formatDoc, insertElementAt, stringify } from "../common"
import { validteUserAppTree, validteUserAppTreeDelete } from "../validators/tree"
import path from "path"

const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)
const rm = promisify(fs.rm)

export function getContentPath (app_id: number, item_id: number) {
    return path.resolve(getDocDir(), app_id + '', DIR_TYPE.DOCS, `${item_id}.md`)
}

export interface TreeSaveBody {
    app_id: number;
    item: UserAppTree;
}
export interface TreeDelBody {
    app_id: number;
    item_id: number;
}
export interface DocBody {
    app_id: number;
    item_id: number;
    parent_id?: number;
    content?: string;
}
export interface TreeMoveBody {
    app_id: number;
    item_id: number;
    parent_id: number;
    anchor_id: number;
    position: "before" | "after" | "inside";
}

async function _save_dir(body: TreeSaveBody, ctx: APIContext) {
    const { item, app_id } = body
    const loginUser = getLoginUser(ctx)
    const res = await getAppDetail(loginUser, app_id)
    if (res.success) {
        const { detail, path_detail } = res.data
        const error = validteUserAppTree(item, detail)
        if (error) {
            return API.error(error + ': ' + JSON.stringify(item))
        }
        const index = detail.tree.findIndex(t => t.id === item.id)
        if (index != -1) {
            Object.assign(detail.tree[index], item)
        } else {
            const content = `# ${item.title}  \n> ${item.description || ""}`
            item.id = detail.tree_max_index++
            await writeFile(getContentPath(app_id, item.id), content)
            detail.tree.push(item)
        }
        await writeFile(path_detail, stringify(detail))
        return API.success({
            detail, item
        })
    } else {
        return API.error(res.message)
    }
}
export class ActionTree {
    /** 获取文档内容 */
    @RouterDecorator("api/get_doc")
    async get_doc(body: DocBody, ctx: APIContext) {
        const { app_id, item_id } = body
        const loginUser = getLoginUser(ctx)
        const contentPath = getContentPath(app_id, item_id)
        const res = await getAppDetail(loginUser, app_id)
        if (res.success) {
            if (!fs.existsSync(contentPath)) {
                return API.error("文档不存在")
            }
            const content = await readFile(contentPath, "utf-8")
            return API.success({ content })
        } else {
            return API.error(res.message)
        }
    }

    /** 修改文档内容 */
    @RouterDecorator("api/save_doc")
    async save_doc(body: DocBody, ctx: APIContext) {
        const { app_id, item_id, parent_id, content } = body
        const { meta } = formatDoc(content)
        const loginUser = getLoginUser(ctx)
        if (!loginUser) {
            return API.error("请先登录")
        }
        const contentPath = getContentPath(app_id, item_id)
        if (!fs.existsSync(contentPath)) {
            return API.error("文档不存在")
        } else {
            await writeFile(contentPath, content || "")
            if (item_id && meta) {
                return _save_dir({ app_id, item: { ...meta, id: item_id, parentId: parent_id } }, ctx)
            } else {
                return API.success({ detail: undefined as unknown as UserAppDetail })
            }
        }
    }

    /** 保存： 新增或者修改共用，根据 item.id 判断 */
    @RouterDecorator("api/save_dir")
    async save_dir(body: TreeSaveBody, ctx: APIContext) {
        return _save_dir(body, ctx)
    }

    /** 删除 */
    @RouterDecorator("api/delete_dir")
    async delete_dir(body: TreeDelBody, ctx: APIContext) {
        const { item_id, app_id } = body
        const loginUser = getLoginUser(ctx)
        const res = await getAppDetail(loginUser, app_id)
        if (res.success) {
            const { detail, path_detail } = res.data
            const error = validteUserAppTreeDelete(item_id, detail)
            if (error) {
                return API.error(error)
            }
            let tree_max_index = 1;
            detail.tree = detail.tree.filter(t => {
                if (t.id === item_id) {
                    return false
                }
                if (tree_max_index <= t.id) {
                    tree_max_index = t.id + 1
                }
                return true
            })
            detail.tree_max_index = tree_max_index;
            await rm(path.resolve(path_detail, '../', DIR_TYPE.DOCS, `${item_id}.md`))
            await writeFile(path_detail, stringify(detail))
            return API.success(detail)
        } else {
            return API.error(res.message)
        }
    }

    /** 移动文档 */
    @RouterDecorator("api/move_dir")
    async move_dir(body: TreeMoveBody, ctx: APIContext) {
        const { app_id, item_id, parent_id, anchor_id, position } = body
        if (!app_id || !item_id || !parent_id && !anchor_id) {
            return API.error("参数错误")
        }
        const loginUser = getLoginUser(ctx)
        const res = await getAppDetail(loginUser, app_id)
        if (res.success) {
            const { detail, path_detail } = res.data
            let itemIndex = -1;
            let parentIndex = -1;
            let anchorIndex = -1;
            for (let i = 0; i < detail.tree.length; i++) {
                const ele = detail.tree[i];
                if (ele.id === item_id) {
                    itemIndex = i
                } else if (ele.id === parent_id) {
                    parentIndex = i
                } else if (ele.id === anchor_id) {
                    anchorIndex = i
                }
            }
            if (itemIndex === -1) {
                return API.error("文档不存在")
            }
            if (parent_id && parentIndex === -1) {
                return API.error("父级文档不存在")
            }
            if (anchor_id && anchorIndex === -1) {
                return API.error("锚点文档不存在")
            }
            const item = detail.tree[itemIndex];
            item.parentId = parent_id
            insertElementAt(detail.tree, itemIndex, anchorIndex + (position != "before" ? 1 : 0))
            await writeFile(path_detail, stringify(detail))
            return API.success(detail)
        }
    }
}